package com.gqqx.weather.controller;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Maps;
import com.google.gson.JsonObject;
import com.gqqx.common.constans.RedisPrefix;
import com.gqqx.weather.Service.WeatherDateService;
import com.gqqx.weather.Service.WeatherService;
import com.gqqx.weather.Service.WeatherStationService;
import com.gqqx.weather.pojo.Weather;
import com.gqqx.weather.pojo.WeatherDate;
import com.gqqx.weather.pojo.WeatherStation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.json.CDL;
import org.json.JSONArray;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component
@Slf4j
public class TestClient {

    @Value("${weather.remoteHost}")
    private String remoteHost; //服务器端的IP地址
    @Value("${weather.remotePort}")
    private int remotePort =9092; //服务器监听的端口,即向该端口发送数据

    private DatagramSocket datagramSocket;

    @Autowired
    private  StringRedisTemplate stringRedisTemplate;

    @Value("${weather.name}")
    private String name;

    @Value("${weather.password}")
    private String password;

    @Value("${weather.localDateTime}")
    private int localDateTime;

    @Value("${weather.filePath}")
    private String filePath;

    @Value("${weather.python}")
    private String python;

    @Autowired
    private WeatherService weatherService;

    @Autowired
    private WeatherStationService weatherStationService;

    @Autowired
    private WeatherDateService weatherDateService;

    public TestClient() throws SocketException {
        datagramSocket = new DatagramSocket();
    }


    /**
     * 请求登录认证
     */
//    @Scheduled(cron = "*/5 * * * * ?")
    public void RequestLogin(){
        try {
            InetAddress address = InetAddress.getByName(remoteHost);
            //将数据包装成Json字符串
            JsonObject object = new JsonObject();
            object.addProperty("code", 1);
//            object.addProperty("name", "zhangsan");
//            object.addProperty("password", "123456");
            object.addProperty("name", name);
            object.addProperty("password", password);
            String content = object.toString();
            System.out.println("客户端发送数据: " + content);//将发送的数据打印在控制台观察
            //发送数据
            byte[] buffer = content.getBytes();
            DatagramPacket packet = new DatagramPacket(buffer, content.getBytes(StandardCharsets.UTF_8).length, address, remotePort);
            System.out.println(remoteHost + "   " + remotePort);
            datagramSocket.send(packet);
            //接收数据
            DatagramPacket inputPacket = new DatagramPacket(new byte[512], 512);
            datagramSocket.receive(inputPacket);
            System.out.println("客户端接收数据: " + new String(inputPacket.getData(), 0, inputPacket.getLength()));
            String result = new String(inputPacket.getData(), 0, inputPacket.getLength());
            log.info(result);
            JSONObject jsonObject= JSONObject.parseObject(result);
            String success = jsonObject.getString("success");
            String token = jsonObject.getString("token");
            if ("1".equals(success)){
                log.info("请求登录成功");
                //将token保存到redis
//                redisTemplate.opsForValue().set("token",jsonObject.getString("token"));
                stringRedisTemplate.opsForValue().set(RedisPrefix.TOKEN_KEY_LOGIN + name,token);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 请求退出登录
     */
    public void RequestLogout(){
        try {
            InetAddress address = InetAddress.getByName(remoteHost);
            //将数据包装成Json字符串
            JsonObject object = new JsonObject();
            object.addProperty("code", 3);
            String token = stringRedisTemplate.opsForValue().get(RedisPrefix.TOKEN_KEY_LOGIN + name);
            object.addProperty("token",token);
            String content = object.toString();
            System.out.println("客户端发送数据: " + content);//将发送的数据打印在控制台观察
            //发送数据
            byte[] buffer = content.getBytes();
            DatagramPacket packet = new DatagramPacket(buffer, content.getBytes(StandardCharsets.UTF_8).length, address, remotePort);
            datagramSocket.send(packet);
            //接收数据
            DatagramPacket inputPacket = new DatagramPacket(new byte[512], 512);
            datagramSocket.receive(inputPacket);
            System.out.println("客户端接收数据: " + new String(inputPacket.getData(), 0, inputPacket.getLength()));
            String result = new String(inputPacket.getData(), 0, inputPacket.getLength());
            JSONObject jsonObject= JSONObject.parseObject(result);
            String success = jsonObject.getString("success");
            if ("1".equals(success)){
                log.info("请求退出成功");
                //将token从redis中删除
                stringRedisTemplate.delete(RedisPrefix.TOKEN_KEY_LOGIN + name);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            datagramSocket.close();
        }
    }

    /**
     * 获取所有气象站编号信息
     */
    public void ObtainNumber(){
        try {
            InetAddress address = InetAddress.getByName(remoteHost);
            //将数据包装成Json字符串
            JsonObject object = new JsonObject();
            object.addProperty("code", 5);
            String token = stringRedisTemplate.opsForValue().get(RedisPrefix.TOKEN_KEY_LOGIN + name);
            object.addProperty("token",token);
            String content = object.toString();
            System.out.println("客户端发送数据: " + content);//将发送的数据打印在控制台观察
            //发送数据
            byte[] buffer = content.getBytes();
            DatagramPacket packet = new DatagramPacket(buffer,content.getBytes(StandardCharsets.UTF_8).length, address, remotePort);
            datagramSocket.send(packet);
            //接收数据
            DatagramPacket inputPacket = new DatagramPacket(new byte[512], 512);
            datagramSocket.receive(inputPacket);
            System.out.println("客户端接收数据: " + new String(inputPacket.getData(), 0, inputPacket.getLength()));
            String result = new String(inputPacket.getData(), 0, inputPacket.getLength());
            JSONObject jsonObject= JSONObject.parseObject(result);
            String code = jsonObject.getString("code");
            if ("6".equals(code)){
                com.alibaba.fastjson.JSONArray data = jsonObject.getJSONArray("data");
                //将json转换成list
                List<WeatherStation> weatherStationList = JSONObject.parseArray(String.valueOf(data),WeatherStation.class);
                //删除表数据
                weatherStationService.remove(new QueryWrapper<>());
                //批量添加
                weatherStationService.saveBatch(weatherStationList);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取指定气象站的数据日期范围
     */
    public void ObtainWeatherDate(){
        try {
            InetAddress address = InetAddress.getByName(remoteHost);
            //将数据包装成Json字符串
            JsonObject object = new JsonObject();
            object.addProperty("code", 7);
//            object.addProperty("token", (String) redisTemplate.opsForValue().get("token"));
            String token = stringRedisTemplate.opsForValue().get(RedisPrefix.TOKEN_KEY_LOGIN + name);
            object.addProperty("token",token);
            //传气象站编号 可能会写死
            object.addProperty("station","1");
            String content = object.toString();
            System.out.println("客户端发送数据: " + content);//将发送的数据打印在控制台观察
            //发送数据
            byte[] buffer = content.getBytes();
            DatagramPacket packet = new DatagramPacket(buffer,content.getBytes(StandardCharsets.UTF_8).length, address, remotePort);
            datagramSocket.send(packet);
            //接收数据
            DatagramPacket inputPacket = new DatagramPacket(new byte[512], 512);
            datagramSocket.receive(inputPacket);
            System.out.println("客户端接收数据: " + new String(inputPacket.getData(), 0, inputPacket.getLength()));
            String result = new String(inputPacket.getData(), 0, inputPacket.getLength());
            JSONObject jsonObject= JSONObject.parseObject(result);
            String code = jsonObject.getString("code");
            String station = jsonObject.getString("station");
            if ("6".equals(code)){
                com.alibaba.fastjson.JSONArray dates = jsonObject.getJSONArray("date");
                WeatherDate weatherDate = new WeatherDate();
                weatherDate.setStation(Long.valueOf(station));
                LambdaQueryWrapper<WeatherDate> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                lambdaQueryWrapper.eq(WeatherDate::getStation,station);
                weatherDateService.remove(lambdaQueryWrapper);
                for (Object date : dates) {
                    weatherDate.setDate((Date) date);
                    weatherDateService.saveOrUpdate(weatherDate);
                }
            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 请求气象数据
     */


//    private String start;
//    private String end;
//    String a = "E:\\weather\\csv_test.csv";
    public void RequestWeatherData(){
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime time = LocalDateTime.now();
        String end = time.format(dateTimeFormatter);
        time = time.plusMinutes(localDateTime);
        String start = time.format(dateTimeFormatter);
        try {
            InetAddress address = InetAddress.getByName(remoteHost);
            //将数据包装成Json字符串
            JsonObject object = new JsonObject();
            object.addProperty("code", 9);
//            object.addProperty("token", (String) redisTemplate.opsForValue().get("token"));
            String token = stringRedisTemplate.opsForValue().get(RedisPrefix.TOKEN_KEY_LOGIN + name);
            object.addProperty("token",token);
            object.addProperty("start",start);
            object.addProperty("end",end);
            String content = object.toString();
            System.out.println("客户端发送数据: " + content);//将发送的数据打印在控制台观察
            //发送数据
            byte[] buffer = content.getBytes();
            DatagramPacket packet = new DatagramPacket(buffer,content.getBytes(StandardCharsets.UTF_8).length, address, remotePort);
            datagramSocket.send(packet);
            //接收数据
            DatagramPacket inputPacket = new DatagramPacket(new byte[512], 512);
            datagramSocket.receive(inputPacket);
            System.out.println("客户端接收数据: " + new String(inputPacket.getData(), 0, inputPacket.getLength()));
            String result = new String(inputPacket.getData(), 0, inputPacket.getLength());
            log.info(result);
            JSONObject jsonObject= JSONObject.parseObject(result);
            String success = jsonObject.getString("success");
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            if ("1".equals(success)) {
//                String sussess = createJsonFile(result, "E:\\weather", "susses");
//                JSONArray jsonArray = new JSONArray("[" + result + "]");
//                String csv = CDL.toString(jsonArray);
//                FileUtils.writeStringToFile(new File("E:\\weather\\csv_test.csv"), csv, StandardCharsets.UTF_8);
                String json = "";
                JSONObject jsons = JSONObject.parseObject(json);
                com.alibaba.fastjson.JSONArray data = jsons.getJSONArray("data");
                List<Map<String,String>> list = new ArrayList<>();
                Weather weather = new Weather();
                for (Object datum : data) {
                    Map<String,String> map = Maps.newLinkedHashMap();
                    List<String> rel = (List<String>) datum;
                    weather.setStation(jsons.getLong("station"));
                    map.put("station", String.valueOf(jsons.getLong("station")));
                    map.put("date",rel.get(0));
                    map.put("temperature",rel.get(1));
                    map.put("humidity",rel.get(2));
                    map.put("speed",rel.get(3));
                    map.put("direction",rel.get(4));
                    map.put("rain",rel.get(5));
                    map.put("sunlight",rel.get(6));
                    map.put("pm25",rel.get(7));
                    map.put("pm10",rel.get(8));
                    weather.setDate(simpleDateFormat.parse(rel.get(0)));
                    weather.setTemperature(rel.get(1));
                    weather.setHumidity(rel.get(2));
                    weather.setSpeed(rel.get(3));
                    weather.setDirection(rel.get(4));
                    weather.setRain(rel.get(5));
                    weather.setSunlight(rel.get(6));
                    weather.setPm25(rel.get(7));
                    weather.setPm10(rel.get(8));
                    list.add(map);
                }
                System.err.println(list);
                JSONArray jsonArray = new JSONArray(JSON.toJSONString(list));
                String csv = CDL.toString(jsonArray);

                SimpleDateFormat sfd1 = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
                String format = sfd1.format(simpleDateFormat.parse(start));
                //生成csv文件
                FileUtils.writeStringToFile(new File(filePath + format + ".csv"), csv, StandardCharsets.UTF_8);
                //执行python脚本  第二个参数是脚本位置 第三个参数是传递要清理的csv文件的位置
                String[] args1 = new String[]{"python", python, filePath + format + ".csv"};
                Process proc = Runtime.getRuntime().exec(args1);//执行PY文件
                BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
                String lines = null;
                while ((lines=in.readLine())!=null){
                    System.out.println(lines);
                }
                in.close();
                proc.waitFor();

                // 读取文件csv文件并添加到数据库中 “GBK"解决文件里中文乱码
                BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream( filePath + format + ".csv"), StandardCharsets.UTF_8));
                reader.readLine(); //第一行信息是标题信息，跳过，如果需要第一行信息，请删除这行代码
                String line;

                //定义list,方便后面批次新增
                List<Weather> weatherResult = new ArrayList<>();
                //循环每行数据
                while ((line = reader.readLine()) !=null) {
                    //分割字符串
                    String item[] = line.split(",");
                    if (item.length > 0){
                        //调用下面的方法，将每列数据赋值到对应的属性中，返回的结果新增到list内
                        weatherResult.add(propertiesAssignment(item));
                    }
                }
                System.out.println(weatherResult);
                weatherService.saveBatch(weatherResult);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 将行数据中每列数据分别添加到对应的属性中，返回实体类
     * @param item
     * @return
     */
    public Weather propertiesAssignment(String[] item) throws Exception {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //获取目标类class
        Class<Weather> clazz = Weather.class;
        //实例化
        Weather weather = clazz.newInstance();

        //获取对象全部属性
        Field[] fields = clazz.getDeclaredFields();
        //循环遍历 当前行数据的列数
        for (int i = 0;i< item.length;i++) {
            //获取方法名
            String methodName = "set" + fields[i + 1].getName().substring(0,1).toUpperCase() + fields[i + 1].getName().substring(1);
            // 获取Method参数类型
            Method method = clazz.getMethod(methodName, fields[i+1].getType());
            // 判断当前属性是什么类型的，将数据进行类型转换
            if ("Integer".equals(fields[i+1].getType().getSimpleName())){
                method.invoke(weather,Integer.parseInt(item[i]));
            } else if ("BigDecimal".equals(fields[i+1].getType().getSimpleName())){
                method.invoke(weather, new BigDecimal(item[i]));
            } else if ("Short".equals(fields[i+1].getType().getSimpleName())){
                method.invoke(weather,Short.valueOf(item[i]));
            } else if ("Double".equals(fields[i+1].getType().getSimpleName())){
                method.invoke(weather,Double.valueOf(item[i]));
            } else if ("Byte".equals(fields[i+1].getType().getSimpleName())){
                method.invoke(weather,Byte.valueOf(item[i]));
            } else if ("String".equals(fields[i+1].getType().getSimpleName())){
                method.invoke(weather,item[i]);
            } else if ("Long".equals(fields[i+1].getType().getSimpleName())) {
                method.invoke(weather,Long.parseLong(item[i]));
            } else if ("Date".equals(fields[i+1].getType().getSimpleName())) {
                method.invoke(weather, simpleDateFormat.parse(item[i]));
            }
        }
        return weather;
    }

}
